﻿#pragma once
#include "Common.h"

namespace forwoard
{
	/*
	* 模板万能引用（也称为转发引用，英文为forwarding references）是C++11引入的一种引用类型
	* 特点：
	  1.表现形式为T&&，其中T是模板参数。
	  2.在特定条件下，编译器会将其（T）解析为左值引用或右值引用。
	  3.能够统一处理左值和右值，适用于泛型编程中的参数传递

	  重要特性：
	  1.当模板参数T被推导为普通类型时，T&&是右值引用。
	  2.当模板参数T被推导为引用类型时，T&&会根据引用折叠规则解析为左值引用。

	  折叠规则(注意这是规则)相当于左值和右值的排列组合:
	  1.& + &、& + &&、&& + & 都折叠为 &（左值引用）。
	  2.&& + && 折叠为 &&（右值引用）。
	*/

	// T&& (整体)，T根据传入变量（本身）和 && 结合（根据折叠规则）
	// 如：int a = 5;   a 本身是一个变量左值 int& -> int& &&(折叠规则) = int&
	// 如：int&& b = 5; b 本身是一个变量左值 int& -> int& &&(折叠规则) = int&。这里可不是说b的类型。可以std::move(b)
	template<typename T>
	void check_referenc(T&& x)
	{
		std::cout << "check T and x : " << std::endl;
		std::cout << "T is lvalue referenc " << std::is_lvalue_reference<T>::value << std::endl;
		std::cout << "T is rvalue referenc " << std::is_rvalue_reference<T>::value << std::endl;
		std::cout << "T is rvalue " << std::is_rvalue_reference<T&&>::value << std::endl;
		// x 的 ​​类型​​ 可能是左值引用或右值引用，但 ​​表达式 x 本身始终是左值​​。这里指的是x的类型
		std::cout << "x type is lvalue referenc " << std::is_lvalue_reference<decltype(x)>::value << std::endl;
		std::cout << "x type is rvalue referenc " << std::is_rvalue_reference<decltype(x)>::value << std::endl;
	}

	void use_check_referenc()
	{
		int a = 5;
		int&& b = 5;

		check_referenc(a);				// T被推导为 int&， 因此 T&& -> int& && -> int&
		check_referenc(10);				// T被推导为 int，  T&& -> int&&
		check_referenc(b);				// T被推导为 int&， 因此 T&& -> int& && -> int&
		check_referenc(std::move(b));	// T被推导为 int，  T&& -> int&&
	}
}
